#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
机器人舞蹈控制系统的打包脚本
专门用于解决PyInstaller打包过程中遇到的问题
"""

import os
import sys
import subprocess
import shutil
from pathlib import Path

def check_dependencies():
    """检查必要的依赖是否已安装"""
    required_packages = [
        'PyQt5',
        'qfluentwidgets', 
        'numpy',
        'requests',
        'serial',
        'pyaudio',
        'matplotlib',
        'websocket'
    ]
    
    missing_packages = []
    for package in required_packages:
        try:
            if package == 'serial':
                import serial
            elif package == 'qfluentwidgets':
                import qfluentwidgets
            elif package == 'websocket':
                import websocket
            else:
                __import__(package)
        except ImportError:
            missing_packages.append(package)
    
    if missing_packages:
        print(f"缺少以下依赖包: {missing_packages}")
        print("请先安装这些依赖包:")
        print(f"pip install {' '.join(missing_packages)}")
        return False
    else:
        print("所有必需依赖包均已安装")
        return True

def create_minimal_spec_file():
    """创建最小化的spec文件"""
    spec_content = '''# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(
    ['fluent_ui.py'],
    pathex=[],
    binaries=[],
    datas=[('config.json', '.'), ('robot_images/*', 'robot_images')],
    hiddenimports=[
        'PyQt5.sip',
        'PyQt5.QtCore',
        'PyQt5.QtGui', 
        'PyQt5.QtWidgets',
        'PyQt5.QtMultimedia',
        'qfluentwidgets',
        'qfluentwidgets.components',
        'qfluentwidgets.components.widgets',
        'qfluentwidgets.common',
        'numpy',
        'numpy.core._methods',
        'numpy.lib.format',
        'requests',
        'serial',
        'pyaudio',
        'matplotlib',
        'matplotlib.backends.backend_qt5agg',
        'websocket',
        'websocket.WebSocketApp',
        # 添加项目模块
        'main_controller',
        'system_state',
        'motion_generator',
        'robot_comm',
        'config_manager',
        'data_control',
        'timeline_editor',
        'music',
        'xfyun_speech',
        'exception_handler',
        'ch',
        'X1_http'
    ],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='robot_dance_controller',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=False,
    disable_windowed_traceback=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)
'''
    
    with open('robot_dance_controller.spec', 'w', encoding='utf-8') as f:
        f.write(spec_content)
    
    print("已创建最小化打包配置文件 robot_dance_controller.spec")

def build_with_pyinstaller():
    """使用PyInstaller进行打包"""
    # 首先检查依赖
    if not check_dependencies():
        return False
    
    # 清理之前的构建
    print("清理之前的构建文件...")
    for folder in ['build', 'dist']:
        if os.path.exists(folder):
            try:
                shutil.rmtree(folder)
                print(f"已删除 {folder} 文件夹")
            except Exception as e:
                print(f"删除 {folder} 失败: {e}")
    
    # 创建spec文件
    print("创建spec文件...")
    create_minimal_spec_file()
    
    # 使用PyInstaller打包
    print("开始使用PyInstaller打包...")
    try:
        cmd = [
            sys.executable, 
            '-m', 
            'PyInstaller', 
            '--noconfirm', 
            'robot_dance_controller.spec'
        ]
        
        print(f"执行命令: {' '.join(cmd)}")
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        if result.returncode == 0:
            print("打包成功完成！")
            print("可执行文件位于 dist/robot_dance_controller/ 目录下")
            return True
        else:
            print("打包过程中出现错误:")
            print("STDOUT:", result.stdout)
            print("STDERR:", result.stderr)
            return False
            
    except Exception as e:
        print(f"执行PyInstaller时发生异常: {e}")
        return False

def build_with_direct_command():
    """使用直接命令行参数打包"""
    # 首先检查依赖
    if not check_dependencies():
        return False
    
    # 清理之前的构建
    print("清理之前的构建文件...")
    for folder in ['build', 'dist']:
        if os.path.exists(folder):
            try:
                shutil.rmtree(folder)
                print(f"已删除 {folder} 文件夹")
            except Exception as e:
                print(f"删除 {folder} 失败: {e}")
    
    # 使用PyInstaller直接打包
    print("开始使用PyInstaller直接命令行打包...")
    try:
        cmd = [
            sys.executable,
            '-m',
            'PyInstaller',
            '--noconfirm',
            '--onedir',
            '--windowed',
            '--name', 'robot_dance_controller',
            '--add-data', 'config.json;.',
            '--add-data', 'robot_images;robot_images',
            # PyQt5相关
            '--hidden-import', 'PyQt5.sip',
            '--hidden-import', 'PyQt5.QtCore',
            '--hidden-import', 'PyQt5.QtGui',
            '--hidden-import', 'PyQt5.QtWidgets',
            '--hidden-import', 'PyQt5.QtMultimedia',
            # Fluent Widgets相关
            '--hidden-import', 'qfluentwidgets',
            '--hidden-import', 'qfluentwidgets.components',
            '--hidden-import', 'qfluentwidgets.components.widgets',
            '--hidden-import', 'qfluentwidgets.common',
            # 数值计算相关
            '--hidden-import', 'numpy',
            '--hidden-import', 'numpy.core._methods',
            '--hidden-import', 'numpy.lib.format',
            # 网络和通信相关
            '--hidden-import', 'requests',
            '--hidden-import', 'serial',
            '--hidden-import', 'websocket',
            '--hidden-import', 'websocket.WebSocketApp',
            # 音频处理相关
            '--hidden-import', 'pyaudio',
            '--hidden-import', 'matplotlib',
            '--hidden-import', 'matplotlib.backends.backend_qt5agg',
            # 项目模块
            '--hidden-import', 'main_controller',
            '--hidden-import', 'system_state',
            '--hidden-import', 'motion_generator',
            '--hidden-import', 'robot_comm',
            '--hidden-import', 'config_manager',
            '--hidden-import', 'data_control',
            '--hidden-import', 'timeline_editor',
            '--hidden-import', 'music',
            '--hidden-import', 'xfyun_speech',
            '--hidden-import', 'exception_handler',
            '--hidden-import', 'ch',
            '--hidden-import', 'X1_http',
            'fluent_ui.py'
        ]
        
        print(f"执行命令: {' '.join(cmd)}")
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        if result.returncode == 0:
            print("打包成功完成！")
            print("可执行文件位于 dist/robot_dance_controller/ 目录下")
            return True
        else:
            print("打包过程中出现错误:")
            print("STDOUT:", result.stdout)
            print("STDERR:", result.stderr)
            return False
            
    except Exception as e:
        print(f"执行PyInstaller时发生异常: {e}")
        return False

def main():
    """主函数"""
    print("机器人舞蹈控制系统打包工具")
    print("=" * 40)
    
    print("选择打包方式:")
    print("1. 使用spec文件打包（推荐）")
    print("2. 使用直接命令行参数打包")
    
    choice = input("请输入选择 (1 或 2): ").strip()
    
    if choice == "1":
        success = build_with_pyinstaller()
    elif choice == "2":
        success = build_with_direct_command()
    else:
        print("无效选择，使用默认方式（spec文件）")
        success = build_with_pyinstaller()
    
    if success:
        print("\n" + "=" * 40)
        print("打包完成！")
        print("可执行文件位于 dist/robot_dance_controller/ 目录下")
        print("将整个 robot_dance_controller 文件夹分发给用户即可")
    else:
        print("\n" + "=" * 40)
        print("打包失败，请检查上面的错误信息")
        print("常见问题及解决方案:")
        print("1. 确保所有依赖包已正确安装")
        print("2. 检查是否有缺失的模块需要添加到hidden-import参数中")
        print("3. 确保config.json和robot_images目录存在")
        print("4. 尝试使用不同的打包方式")
        print("5. 检查是否有语法错误或导入错误")

if __name__ == "__main__":
    main()